﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Ceremony.API.Model;
using Ceremony.API.ParameterModel;
using Ceremony.API.ViewModel;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Ceremony.API.Controllers
{
    [Route("api/v1/bobing")]
    [ApiController]
    public class BobingController : ControllerBase
    {
        private readonly ILogger<BobingController> _logger;
        private readonly CeremonyContext _context;
        private readonly CeremonySettings _settings;
        private readonly string _remoteIP;
        private string[] _ReturnMessage = { "真糟糕，没有中！", "还能说什么，再接再厉！", "喝杯酒休息一下！", "天灵灵地灵灵，就我不灵！", "吹吹风，反省一下！", "摇不中啊换个姿势吧！", "人生最重要两个字是坚持！", "么么哒~", "加油💪", "🤭" };
        /// <summary>
        /// 开始标识（0：未开始，1：开始，2：已结束）
        /// </summary>
        private const string StartTagKey = "StartTag";
        /// <summary>
        /// 用户表
        /// </summary>
        private const string BobingUserKey = "BobingUser";
        /// <summary>
        /// 奖项设置
        /// </summary>
        private const string PrizeSettingKey = "PrizeSetting";

        private const string UserAuthorizeKey = "UserAuthorize_";
        public BobingController(ILogger<BobingController> logger,
            CeremonyContext context,
            IOptionsSnapshot<CeremonySettings> settings)
        {
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
            _context = context ?? throw new ArgumentNullException(nameof(context));
            _settings = settings.Value ?? throw new ArgumentNullException(nameof(settings));
            _remoteIP = settings.Value.RemoteIP;
        }
        /// <summary>
        /// 用户注册授权
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("register")]
        [HttpPost]
        [ProducesResponseType(typeof(RegisterUserResponse), (int)HttpStatusCode.OK)]
        [ProducesResponseType((int)HttpStatusCode.BadRequest)]
        public async Task<ActionResult<RegisterUserResponse>> RegisterUserAsync([FromBody] RegisterRequest request)
        {
            RegisterUserResponse model = new RegisterUserResponse();
            try
            {
                var authorizes = _context.Authorizes.Where(t => t.Code == request.AuthorizationCode);
                if (authorizes.Any())
                {
                    //从redis中获取当前用户
                    var bouser = await RedisHelper.HGetAsync<BobingUser>($"{BobingUserKey}", $"{UserAuthorizeKey}{request.AuthorizationCode}");
                    //未注册
                    if (bouser == null)
                    {
                        BobingUser user = new BobingUser(request.AuthorizationCode, request.UserName, _settings.Times);
                        await RedisHelper.HSetAsync($"{ BobingUserKey}", $"{UserAuthorizeKey}{user.AuthorizationCode}", user);
                        //发布创建成功记录信息
                        await RedisHelper.LPushAsync<BobingUser>(_settings.ChannelTaskName, user);
                        model.ResponseCode = 0;
                        model.User = new RegisterUser
                        {
                            UserId = user.Id,
                            UserName = user.UserName,
                            AuthorizationCode = user.AuthorizationCode,
                            Times = user.Times,
                        };
                    }//已注册，直接返回当前用户
                    else
                    {
                        model.ResponseCode = 4;
                        bouser.UserName = request.UserName;
                        model.User = new RegisterUser
                        {
                            UserId = bouser.Id,
                            UserName = bouser.UserName,
                            AuthorizationCode = bouser.AuthorizationCode,
                            Times = bouser.Times,
                        };
                        await RedisHelper.HSetAsync($"{BobingUserKey}", $"{UserAuthorizeKey}{request.AuthorizationCode}", bouser);
                        //发布更新通知
                        await RedisHelper.LPushAsync<BobingUser>(_settings.ChannelTaskName, bouser);
                    }
                }
                else
                {
                    model.ResponseCode = 2;
                }
            }
            catch (Exception ex)
            {
                model.ResponseCode = 3;
                _logger.LogError("用户注册失败:" + ex.Message);
            }
            return Ok(model);
        }
        /// <summary>
        /// 设置活动开始或未开始（0：未开始，1：开始，2：已结束）
        /// </summary>
        /// <returns></returns>
        [Route("startactive")]
        [HttpPost]
        [ProducesResponseType((int)HttpStatusCode.OK)]
        [ProducesResponseType((int)HttpStatusCode.BadRequest)]
        public async Task<IActionResult> EnableStartActivityAsync([FromBody] EnableStartRequest request)
        {
            bool result = await RedisHelper.SetAsync($"{StartTagKey}", request.StartTag);
            if (result)
            {
                if (request.StartTag == 0)
                {
                    await RedisHelper.DelAsync($"{PrizeSettingKey}");
                    await RedisHelper.DelAsync(BobingUserKey);
                    var results = _context.BobingPrizeResults;
                    _context.BobingPrizeResults.RemoveRange(results);
                    var users = _context.BobingUsers;
                    _context.BobingUsers.RemoveRange(users);
                    await _context.SaveChangesAsync();
                }
                else
                {
                    var boBingPrizes = await _context.BobingPrizes.ToListAsync();
                    foreach (var item in boBingPrizes)
                    {
                        await RedisHelper.SAddAsync<BobingPrize>(PrizeSettingKey, item);
                    }
                }
                return Ok();
            }
            else
                return BadRequest();
        }
        /// <summary>
        /// 开始博饼
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("start")]
        [HttpPost]
        [ProducesResponseType(typeof(BobingResultViewModel),(int)HttpStatusCode.OK)]
        [ProducesResponseType((int)HttpStatusCode.BadRequest)]
        public async Task<ActionResult<BobingResultViewModel>> StartActivityAsync([FromBody]StartBobingRequest request)
        {
            BobingResultViewModel model = new BobingResultViewModel();
            try
            {
                BobingUser currentUser = await RedisHelper.HGetAsync<BobingUser>($"{BobingUserKey}", $"{UserAuthorizeKey}{request.AuthorizationCode}"); ;
                //判断当前用户是否注册
                if (currentUser == null)
                {
                    model.CanBobing = 5;
                    model.Message = "你还未授权，不能参加活动";
                    return Ok(model);
                }
                //开始标识
                int startTag = await RedisHelper.GetAsync<int>($"{StartTagKey}");
                if (startTag == 0)
                {
                    model.CanBobing = 2;
                    model.Message = "活动未开始";
                    return Ok(model);
                }
                else if (startTag == 1)
                {
                    //当前用户是否已经次数为0
                    if (currentUser.Times <= 0)
                    {
                        model.CanBobing = 4;
                        model.Message = "抱歉，您的次数已用完";
                        return Ok(model);
                    }
                    //开始随机设置骰子点数(六个骰子)
                    Random random = new Random();
                    List<int> points = new List<int>();
                    for (int i = 0; i < 6; i++)
                    {
                        int randomNum = random.Next(1, 7);
                        points.Add(randomNum);
                    }
                    //判断奖项
                    int oneNum = points.Where(t => t == 1).Count();
                    int twoNum = points.Where(t => t == 2).Count();
                    int threeNum = points.Where(t => t == 3).Count();
                    int fourNum = points.Where(t => t == 4).Count();
                    int fiveNum = points.Where(t => t == 5).Count();
                    int sixNum = points.Where(t => t == 6).Count();
                    model.Points = points;
                    if (fiveNum == 4 && oneNum == 2)//状元插金花
                    {
                        model.PrizeType = 12;
                        model.Message = "状元插金花";
                    }
                    else if (fiveNum == 6)//六勃红
                    {
                        model.PrizeType = 11;
                        model.Message = "状元（六勃红）";
                    }
                    else if (oneNum == 6) //状元（遍地锦）
                    {
                        model.PrizeType = 10;
                        model.Message = "状元（遍地锦）";
                    }
                    else if (twoNum == 6 ||
                        threeNum == 6 ||
                        fiveNum == 6 ||
                        sixNum == 6)//状元（六勃黑）
                    {
                        model.PrizeType = 9;
                        model.Message = "状元（六勃黑）";
                    }
                    else if (fourNum == 5)//状元（五红）
                    {
                        model.PrizeType = 8;
                        model.Message = "状元（五红）";
                    }
                    else if (oneNum == 5 ||
                        twoNum == 5 ||
                        threeNum == 5 ||
                        fiveNum == 5 ||
                        sixNum == 5)//五子
                    {
                        model.PrizeType = 7;
                        model.Message = "状元（五子）";
                    }
                    else if (fourNum == 4)//状元（四红）
                    {
                        model.PrizeType = 6;
                        model.Message = "状元（四红）";
                    }
                    else if (oneNum == 1 &&
                        twoNum == 1 &&
                        threeNum == 1 &&
                        fourNum == 1 &&
                        fiveNum == 1 &&
                        sixNum == 1)//对堂
                    {
                        model.PrizeType = 5;
                        model.Message = "对堂";
                    }
                    else if (fourNum == 3)//三红
                    {
                        model.PrizeType = 4;
                        model.Message = "三红";
                    }
                    else if (oneNum == 4 ||
                        twoNum == 4 ||
                        threeNum == 4 ||
                        fiveNum == 4 ||
                        sixNum == 4)
                    {
                        model.PrizeType = 3;
                        model.Message = "四进";
                    }
                    else if (fourNum == 2)//二举
                    {
                        model.PrizeType = 2;
                        model.Message = "二举";
                    }
                    else if (fourNum == 1)//一秀
                    {
                        model.PrizeType = 1;
                        model.Message = "一秀";

                    }
                    else //未中奖
                    {
                        model.CanBobing = 1;
                        model.PrizeType = 0;
                        Random rd = new Random();
                        int rdNum = rd.Next(0, _ReturnMessage.Length);
                        model.Message = _ReturnMessage[rdNum];
                    }
                    if (model.PrizeType > 0)
                    {
                        model.CanBobing = 1;
                        //计算奖项积分
                        var prizeSettings = await RedisHelper.SMembersAsync<BobingPrize>(PrizeSettingKey);
                        var prizeSet = prizeSettings.FirstOrDefault(t => t.PrizeType == model.PrizeType);
                        //发布同步中奖信息到服务
                        SyncPrizeResult prizeResult = new SyncPrizeResult(currentUser.AuthorizationCode, prizeSet.Id, string.Join(",", model.Points));
                        await RedisHelper.LPushAsync<SyncPrizeResult>(_settings.BobingPrizeTaskName, prizeResult);
                    }
                    //次数减少
                    currentUser.Times--;
                    await RedisHelper.HSetAsync(BobingUserKey, $"{UserAuthorizeKey}{request.AuthorizationCode}", currentUser);
                    model.Times = currentUser.Times;
                }
                else if (startTag == 2)
                {
                    model.CanBobing = 3;
                }
                return Ok(model);
            }
            catch (Exception ex)
            {
                model.CanBobing = 10;
                _logger.LogError("用户开始博饼失败:" + ex.Message);
            }
            return Ok(model);
        }
        /// <summary>
        /// 用户获奖记录
        /// </summary>
        /// <param name="authorizeCode"></param>
        /// <returns></returns>
        [HttpGet]
        [Route("prizes/{authorizeCode}")]
        [ProducesResponseType(typeof(IEnumerable<PrizeRecordResponse>), (int)HttpStatusCode.OK)]
        [ProducesResponseType((int)HttpStatusCode.BadRequest)]
        public async Task<ActionResult<IEnumerable<PrizeRecordResponse>>> GetPrizeRecordsAsync(string authorizeCode)
        {
            List<PrizeRecordResponse> prizeRecords = new List<PrizeRecordResponse>();
            var user = await _context.BobingUsers.FirstOrDefaultAsync(t => t.AuthorizationCode == authorizeCode);
            if (user != null)
            {
                var prizes = _context.BobingPrizeResults.Where(t => t.UserId == user.Id).OrderBy(t => t.CreateTime);
                var prizeSettings = await RedisHelper.SMembersAsync<BobingPrize>(PrizeSettingKey);
                foreach (var item in prizes)
                {
                    var prizeSet = prizeSettings.FirstOrDefault(t => t.Id == item.BobingPrizeId);
                    string[] prizeResult = item.PrizeResult.Split(',');
                    List<string> imageSource = new List<string>();
                    for (int i = 0; i < prizeResult.Length; i++)
                    {
                        //骰子点数对应照片
                        switch (prizeResult[i])
                        {
                            case "1":
                                imageSource.Add($"{_remoteIP}/guizeshai1.png");
                                break;
                            case "2":
                                imageSource.Add($"{_remoteIP}/guizeshai2.png");
                                break;
                            case "3":
                                imageSource.Add($"{_remoteIP}/guizeshai3.png");
                                break;
                            case "4":
                                imageSource.Add($"{_remoteIP}/guizeshai4.png");
                                break;
                            case "5":
                                imageSource.Add($"{_remoteIP}/guizeshai5.png");
                                break;
                            case "6":
                                imageSource.Add($"{_remoteIP}/guizeshai6.png");
                                break;
                            default:
                                imageSource.Add($"{_remoteIP}/guizeshai.png");
                                break;
                        }
                    }
                    prizeRecords.Add(new PrizeRecordResponse
                    {
                        ImageSource = imageSource,
                        PrizeName = prizeSet.PrizeName,
                        Integral = prizeSet.Integral,
                        UserId = item.UserId
                    });
                }
            }
            return Ok(prizeRecords);
        }
        /// <summary>
        /// 创建奖项
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("prize")]
        [ProducesResponseType((int)HttpStatusCode.OK)]
        [ProducesResponseType((int)HttpStatusCode.BadRequest)]
        public async Task<IActionResult> CreatePrizeAsync([FromBody] SettingBobingRequest request)
        {
            int count = await _context.BobingPrizes.Where(t => t.PrizeType == request.PrizeType).CountAsync();
            BobingResponseCode response = new BobingResponseCode();
            if (count > 0)
            {
                response.ResponseCode = 1;
            }
            else
            {
                _context.BobingPrizes.Add(new BobingPrize(request.PrizeType, request.PrizeName, request.Integral));
                int result = await _context.SaveChangesAsync();
                if (result > 0)
                    response.ResponseCode = 0;
                else
                    response.ResponseCode = 2;
            }
            return Ok(response);
        }
        /// <summary>
        /// 排行榜
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("rank")]
        [ProducesResponseType(typeof(IEnumerable<RankingResponse>), (int)HttpStatusCode.OK)]
        [ProducesResponseType((int)HttpStatusCode.BadRequest)]
        public async Task<ActionResult<IEnumerable<RankingResponse>>> GetRankingAsync()
        {
            var userRecords = from a in _context.BobingPrizeResults
                              join b in _context.BobingPrizes on a.BobingPrizeId equals b.Id
                              select new
                              {
                                  UserId = a.UserId,
                                  Integral = b.Integral
                              };
            var prizes = await userRecords.GroupBy(t => t.UserId).Select(k => new
            {
                UserId = k.Key,
                Integral = k.Sum(f => f.Integral)
            }).OrderByDescending(z => z.Integral).ToListAsync();
            List<RankingResponse> rankResponses = new List<RankingResponse>();
            var users = await _context.BobingUsers.ToListAsync();
            var userPrizes = from a in users
                             join b in prizes on a.Id equals b.UserId
                             select new
                             {
                                 UserId = a.Id,
                                 UserName = a.UserName,
                                 Integral = b.Integral,
                                 AuthorizeCode = a.AuthorizationCode
                             };
            int i = 0;
            userPrizes = userPrizes.OrderByDescending(t => t.Integral);
            foreach (var item in userPrizes)
            {
                RankingResponse response = new RankingResponse 
                { 
                    RankNum = i + 1,
                    Integral = item.Integral
                };
                //排行中显示的图片
                if (i == 0)
                {
                    response.ImageUrl = _settings.RemoteIP + "/guanjun.png";
                }
                else if(i == 1)
                {
                    response.ImageUrl = _settings.RemoteIP + "/yajun.png"; ;
                }
                else if(i == 2)
                {
                    response.ImageUrl = _settings.RemoteIP + "/jijun.png"; ;
                }
                else
                {
                    response.ImageUrl = _settings.RemoteIP + "/flower.png"; ;
                }
                response.UserName = item.UserName;
                response.AuthorizeCode = item.AuthorizeCode;
                rankResponses.Add(response);
                i++;
            }
            return Ok(rankResponses);
        }
    }
}
